#include "Gutter.h"
#include "Constants.h"
#include<iostream>
#include<fstream>
#include <string>
#include <utils\FileUtils.h>
#include <pipeline\PAKWriter.h>

Gutter::Gutter(void) : ds::Node("Gutter",true) {	
	m_Tiles.create(12,7);
	m_Tiles.clear(0);
	m_Pieces.create(MAX_X,MAX_Y);
	m_Pieces.clear(0);	
	m_Selection = new ds::ScreenQuad("Selection","TexturesMaterial",512,true);	
	gEngine->getWorld().attachNode(m_Selection,"Background");
	m_Grid = new ds::ScreenQuad("Grid","TexturesMaterial",512);	
	gEngine->getWorld().attachNode(m_Grid,"Background");
	m_Borders = new ds::ScreenQuad("Borders","TexturesMaterial",512);	
	gEngine->getWorld().attachNode(m_Borders,"Background");	
}

Gutter::~Gutter(void) {
}

void Gutter::update(float elapsed) {
	m_Selection->clear();
	for ( int x = 0 ; x < MAX_X; ++x ) {
		for ( int y = 0; y < MAX_Y; ++y ) {
			int s = m_Pieces.get(x,y);
			if ( s == 2 ) {
				int xp = START_X + x * 35;
				int yp = START_Y + y * 35;
				m_Selection->add(ds::Vec3(xp,yp,1),ds::Vec3(35,35,0),ds::Rect(72,290,35,35));						
			}
		}
	}
	m_Selection->rebuild();
}

void Gutter::markCell(int gx,int gy) {
	if ( m_Pieces.get(gx,gy) == 1 ) {
		LOG(logINFO) << "markCell " << gx << " " << gy;
		m_Pieces.set(gx,gy,2);
		++m_CellCounter;		
	}
}

bool Gutter::isAllowed(int gx,int gy) {
	int c = m_Pieces.get(gx,gy);
	if ( c > 0 ) {
		return true;
	}
	return false;
}

bool Gutter::isBlockAvailable(int gx,int gy) {
	for ( int i = 0; i < 4; ++i ) {
		if ( !isAllowed( gx + BLOCK_X[i], gy + BLOCK_Y[i]) ) {
			return false;
		}
	}	
	return true;
}

void Gutter::loadTextLevelFiles() {
	std::vector<std::string> files;
	ds::FileUtils::listDirectory("data",files);
	for ( size_t i = 0; i < files.size(); ++i ) {
		Level* l = new Level;
		loadTextLevel("data\\"+files[i],l);
		m_Levels.push_back(l);
	}
	LOG(logINFO) << "number of levels " << m_Levels.size();	
	FILE* file;
	file = fopen("Levels.data","wb");
	if ( file ) {
		uint32 sz = m_Levels.size();
		fwrite(&sz,sizeof(uint32),1,file);
		for ( size_t i = 0; i < m_Levels.size();++i ) {
			Level* lvl = m_Levels[i];
			fwrite(lvl,sizeof(Level),1,file);
		}
	}
	fclose(file);
}

void Gutter::getLevelNames(std::vector<std::string>& levelNames) {
	for ( size_t i = 0; i < m_Levels.size();++i ) {
		Level* lvl = m_Levels[i];
		levelNames.push_back(lvl->name);
	}
}

void Gutter::loadTextLevel(const std::string& fileName,Level* level) {
	std::string line;
	std::ifstream myfile(fileName);
	int lc = 0;
	bool first = true;
	int type = 0;
	int maxY = MAX_Y / 2;
	int maxX = MAX_X / 2;
	if (myfile.is_open()) {
		while ( myfile ) {
			getline (myfile,line);
			if ( first ) {
				sprintf(level->name,"%s",line.c_str());
				first = false;
			}
			else {
				if ( lc < maxY ) {
					for ( int i = 0; i < maxX; ++i ) {
						char c = line[i];
						if ( c == 'x' ) {
							type = 1;
							m_Total += 4;
						}
						else {
							type = 0;
						}
						int index = i + lc * maxX;
						assert(index < 84);
						level->tiles[index] = type;						
					}
					++lc;
				}
			}
		}
	}
}

void Gutter::loadTextLevel(int levelIndex) {
	m_CellCounter = 0;
	m_Total = 0;
	int maxY = MAX_Y / 2;
	int maxX = MAX_X / 2;
	/*
	std::string line;
	std::string name = "data\\Level"+ds::string::to_string(lvl)+".txt";
	std::ifstream myfile(name);
	int lc = 0;
	int type = 0;
	
	if (myfile.is_open()) {
		while ( myfile ) {
			getline (myfile,line);
			if ( lc < maxY ) {
				for ( int i = 0; i < maxX; ++i ) {
					char c = line[i];
					if ( c == 'x' ) {
						type = 1;
						m_Total += 4;
					}
					else {
						type = 0;
					}
					m_Tiles.set(i,lc,type);
					int spx = i *2;
					int spy = lc * 2;
					m_Pieces.set(spx,spy,type);
					m_Pieces.set(spx+1,spy,type);
					m_Pieces.set(spx,spy+1,type);
					m_Pieces.set(spx+1,spy+1,type);
				}
				++lc;
			}
		}
	}
	*/
	Level* lvl = m_Levels[levelIndex];
	for ( int x = 0; x < maxX; ++x ) {
		for ( int y = 0; y < maxY; ++y ) {
			int index = x + y * maxX;
			int type = lvl->tiles[index];
			if ( type == 1 ) {
				m_Total += 4;
			}
			m_Tiles.set(x,y,type);
			int spx = x *2;
			int spy = y * 2;
			m_Pieces.set(spx,spy,type);
			m_Pieces.set(spx+1,spy,type);
			m_Pieces.set(spx,spy+1,type);
			m_Pieces.set(spx+1,spy+1,type);
		}
	}
	m_Grid->clear();
	for ( int x = 0; x < maxX; ++x ) {
		int xp = START_X + x * 70;
		for ( int y = 0; y < maxY; ++y ) {
			int yp = START_Y + y * 70;
			int p = m_Tiles.get(x,y);
			if ( p == 1 ) {
				m_Grid->add(ds::Vec3(xp,yp,1),ds::Vec3(70,70,0),ds::Rect(0,0,70,70));		
			}
		}
	}
	m_Grid->rebuild();
	m_Borders->clear();
	for ( int x = 0; x < maxX; ++x ) {
		int xp = START_X + x * 70;
		for ( int y = 0; y < maxY; ++y ) {
			int yp = START_Y + y * 70;
			int p = m_Tiles.get(x,y);
			if ( p == 1 ) {
				// top
				if ( !hasAdjacent(x,y-1) ) {
					m_Borders->add(ds::Vec3(xp,yp-9,1),ds::Vec3(70,9,0),ds::Rect(0,290,70,9));		
				}				
				// left
				if ( !hasAdjacent(x-1,y) ) {
					m_Borders->add(ds::Vec3(xp-9,yp,1),ds::Vec3(9,70,0),ds::Rect(0,270,9,70));		
				}	
				// top left corner
				if ( !hasAdjacent(x,y-1) && !hasAdjacent(x-1,y) ) {
					m_Borders->add(ds::Vec3(xp-9,yp-9,1),ds::Vec3(9,9,0),ds::Rect(0,290,9,9));
					m_Borders->add(ds::Vec3(xp-9,yp-9,1),ds::Vec3(9,9,0),ds::Rect(0,270,9,9));		
				}	
				// top right corner
				if ( !hasAdjacent(x,y-1) && !hasAdjacent(x+1,y) ) {
					m_Borders->add(ds::Vec3(xp+70,yp-9,1),ds::Vec3(9,9,0),ds::Rect(0,290,9,9));
					m_Borders->add(ds::Vec3(xp+70,yp-9,1),ds::Vec3(9,9,0),ds::Rect(0,270,9,9));		
				}	
				// right
				if ( !hasAdjacent(x+1,y) ) {
					m_Borders->add(ds::Vec3(xp+70,yp,1),ds::Vec3(9,70,0),ds::Rect(0,270,9,70));		
				}							
				// bottom
				if ( !hasAdjacent(x,y+1) ) {
					m_Borders->add(ds::Vec3(xp,yp+70,1),ds::Vec3(70,9,0),ds::Rect(0,290,70,9));		
				}		
				// bottom left corner
				if ( !hasAdjacent(x,y+1) && !hasAdjacent(x-1,y) ) {
					m_Borders->add(ds::Vec3(xp-9,yp+70,1),ds::Vec3(9,9,0),ds::Rect(0,290,9,9));
					m_Borders->add(ds::Vec3(xp-9,yp+70,1),ds::Vec3(9,9,0),ds::Rect(0,270,9,9));		
				}	
				// bottom right corner
				if ( !hasAdjacent(x,y+1) && !hasAdjacent(x+1,y) ) {
					m_Borders->add(ds::Vec3(xp+70,yp+70,1),ds::Vec3(9,9,0),ds::Rect(0,290,9,9));
					m_Borders->add(ds::Vec3(xp+70,yp+70,1),ds::Vec3(9,9,0),ds::Rect(0,270,9,9));		
				}	
			}
		}
	}
	m_Borders->rebuild();
	LOG(logINFO) << "total number of pieces " << m_Total;
}

bool Gutter::hasAdjacent(int gx,int gy) {
	if ( !m_Tiles.isValid(gx,gy) || ( m_Tiles.isValid(gx,gy) && m_Tiles.get(gx,gy) == 0 ) ) {
		return false;
	}	
	return true;
}